package de.endrullis.idea.postfixtemplates.language;

import com.intellij.lexer.FlexLexer;
import com.intellij.psi.tree.IElementType;
import de.endrullis.idea.postfixtemplates.language.psi.CptTypes;
import com.intellij.psi.TokenType;

%%

%class CptLexer
%implements FlexLexer
%unicode
%function advance
%type IElementType
%eof{  return;
%eof}

CRLF=\R
WHITE_SPACE=[\ \t]
TEMPLATE_DESCRIPTION_FIRST_CHAR=[^ \n\f]
TEMPLATE_DESCRIPTION_CHAR=[^\n\f]
END_OF_LINE_COMMENT=("#")[^\r\n]*
SEPARATOR=[:=]
DOT=[.]
BRACKET_OPEN=\[
BRACKET_CLOSE=\]
MAP=("->"|"→")
NAME_CHAR=[a-zA-Z0-9_]
CLASS_NAME_CHAR=[a-zA-Z0-9._]
TEMPLATE_VARIABLE_START_CHAR=[$]
TEMPLATE_VARIABLE_CHAR=[^$\r\n\f\t\\:]
TEMPLATE_VARIABLE_SEPARATOR=[:]
TEMPLATE_CODE_FIRST_CHAR=[^ $\n\f\\]
TEMPLATE_CODE_CHAR=[^$\n\f\\]
ESCAPE_CHAR="\\"
ANY_CHAR=[^\n\f]

%state WAITING_DESCRIPTION
%state WAITING_TEMPLATE_CODE
%state WAITING_TEMPLATE_CODE_CON
%state WAITING_TEMPLATE_ESC
%state WAITING_TEMPLATE_VAR_NAME
%state WAITING_TEMPLATE_VAR_NAME_NEXT
%state WAITING_TEMPLATE_VAR_EXPRESSION
%state WAITING_TEMPLATE_VAR_EXPRESSION_ESC
%state WAITING_TEMPLATE_VAR_VALUE
%state WAITING_TEMPLATE_VAR_VALUE_ESC

%%

<YYINITIAL> {END_OF_LINE_COMMENT}                            { yybegin(YYINITIAL); return CptTypes.COMMENT; }
<YYINITIAL> {DOT}{NAME_CHAR}+                                { yybegin(YYINITIAL); return CptTypes.TEMPLATE_NAME; }
<YYINITIAL> {CLASS_NAME_CHAR}+                               { yybegin(YYINITIAL); return CptTypes.CLASS_NAME; }
<YYINITIAL> {BRACKET_OPEN}                                   { yybegin(YYINITIAL); return CptTypes.BRACKET_OPEN; }
<YYINITIAL> {BRACKET_CLOSE}                                  { yybegin(YYINITIAL); return CptTypes.BRACKET_CLOSE; }
<YYINITIAL> {MAP}                                            { yybegin(WAITING_TEMPLATE_CODE); return CptTypes.MAP; }
<YYINITIAL> {SEPARATOR}                                      { yybegin(WAITING_DESCRIPTION); return CptTypes.SEPARATOR; }
<YYINITIAL> {TEMPLATE_VARIABLE_START_CHAR}                   { yybegin(WAITING_TEMPLATE_VAR_NAME); return CptTypes.TEMPLATE_VARIABLE_START; }


<WAITING_DESCRIPTION> {CRLF}({CRLF}|{WHITE_SPACE})+          { yybegin(YYINITIAL); return TokenType.WHITE_SPACE; }
<WAITING_DESCRIPTION> {WHITE_SPACE}+                         { yybegin(WAITING_DESCRIPTION); return TokenType.WHITE_SPACE; }
<WAITING_DESCRIPTION> {TEMPLATE_DESCRIPTION_FIRST_CHAR}{TEMPLATE_DESCRIPTION_CHAR}* { yybegin(YYINITIAL); return CptTypes.TEMPLATE_DESCRIPTION; }


<WAITING_TEMPLATE_CODE> {CRLF}({CRLF}|{WHITE_SPACE})+        { yybegin(YYINITIAL); return TokenType.WHITE_SPACE; }
<WAITING_TEMPLATE_CODE> {WHITE_SPACE}+                       { yybegin(WAITING_TEMPLATE_CODE_CON); return TokenType.WHITE_SPACE; }
<WAITING_TEMPLATE_CODE> {TEMPLATE_CODE_FIRST_CHAR}{TEMPLATE_CODE_CHAR}* { yybegin(WAITING_TEMPLATE_CODE_CON); return CptTypes.TEMPLATE_CODE; }
<WAITING_TEMPLATE_CODE> {TEMPLATE_VARIABLE_START_CHAR}       { yybegin(WAITING_TEMPLATE_VAR_NAME); return CptTypes.TEMPLATE_VARIABLE_START; }
<WAITING_TEMPLATE_CODE> {ESCAPE_CHAR}                        { yybegin(WAITING_TEMPLATE_ESC); return CptTypes.TEMPLATE_ESCAPE; }

<WAITING_TEMPLATE_CODE_CON> {CRLF}({CRLF}|{WHITE_SPACE})+    { yybegin(YYINITIAL); return TokenType.WHITE_SPACE; }
<WAITING_TEMPLATE_CODE_CON> {WHITE_SPACE}+                   { yybegin(WAITING_TEMPLATE_CODE_CON); return CptTypes.TEMPLATE_CODE; }
<WAITING_TEMPLATE_CODE_CON> {TEMPLATE_CODE_CHAR}+            { yybegin(WAITING_TEMPLATE_CODE_CON); return CptTypes.TEMPLATE_CODE; }
<WAITING_TEMPLATE_CODE_CON> {TEMPLATE_VARIABLE_START_CHAR}   { yybegin(WAITING_TEMPLATE_VAR_NAME); return CptTypes.TEMPLATE_VARIABLE_START; }
<WAITING_TEMPLATE_CODE_CON> {ESCAPE_CHAR}                    { yybegin(WAITING_TEMPLATE_ESC); return CptTypes.TEMPLATE_ESCAPE; }

<WAITING_TEMPLATE_ESC> ({CRLF}|{ANY_CHAR}){WHITE_SPACE}*     { yybegin(WAITING_TEMPLATE_CODE_CON); return CptTypes.TEMPLATE_CODE; }


<WAITING_TEMPLATE_VAR_NAME> {TEMPLATE_VARIABLE_CHAR}+        { yybegin(WAITING_TEMPLATE_VAR_NAME_NEXT); return CptTypes.TEMPLATE_VARIABLE_NAME; }
<WAITING_TEMPLATE_VAR_NAME> {TEMPLATE_VARIABLE_START_CHAR}   { yybegin(WAITING_TEMPLATE_CODE_CON); return CptTypes.TEMPLATE_ESCAPE; }

<WAITING_TEMPLATE_VAR_NAME_NEXT> {TEMPLATE_VARIABLE_SEPARATOR}    { yybegin(WAITING_TEMPLATE_VAR_EXPRESSION); return CptTypes.TEMPLATE_VARIABLE_SEPARATOR; }
<WAITING_TEMPLATE_VAR_NAME_NEXT> {TEMPLATE_VARIABLE_START_CHAR}   { yybegin(WAITING_TEMPLATE_CODE_CON); return CptTypes.TEMPLATE_VARIABLE_END; }


<WAITING_TEMPLATE_VAR_EXPRESSION> {TEMPLATE_VARIABLE_CHAR}+       { yybegin(WAITING_TEMPLATE_VAR_EXPRESSION); return CptTypes.TEMPLATE_VARIABLE_EXPRESSION; }
<WAITING_TEMPLATE_VAR_EXPRESSION> {TEMPLATE_VARIABLE_SEPARATOR}   { yybegin(WAITING_TEMPLATE_VAR_VALUE); return CptTypes.TEMPLATE_VARIABLE_SEPARATOR; }
<WAITING_TEMPLATE_VAR_EXPRESSION> {TEMPLATE_VARIABLE_START_CHAR}  { yybegin(WAITING_TEMPLATE_CODE_CON); return CptTypes.TEMPLATE_VARIABLE_END; }
<WAITING_TEMPLATE_VAR_EXPRESSION> {ESCAPE_CHAR}                   { yybegin(WAITING_TEMPLATE_VAR_EXPRESSION_ESC); return CptTypes.TEMPLATE_VARIABLE_EXPRESSION; }

<WAITING_TEMPLATE_VAR_EXPRESSION_ESC> ({CRLF}|{ANY_CHAR}){WHITE_SPACE}*  { yybegin(WAITING_TEMPLATE_VAR_EXPRESSION); return CptTypes.TEMPLATE_VARIABLE_EXPRESSION; }


<WAITING_TEMPLATE_VAR_VALUE> {TEMPLATE_VARIABLE_CHAR}+       { yybegin(WAITING_TEMPLATE_VAR_VALUE); return CptTypes.TEMPLATE_VARIABLE_VALUE; }
<WAITING_TEMPLATE_VAR_VALUE> {TEMPLATE_VARIABLE_SEPARATOR}   { yybegin(WAITING_TEMPLATE_VAR_VALUE); return CptTypes.TEMPLATE_VARIABLE_SEPARATOR; }
<WAITING_TEMPLATE_VAR_VALUE> {TEMPLATE_VARIABLE_START_CHAR}  { yybegin(WAITING_TEMPLATE_CODE_CON); return CptTypes.TEMPLATE_VARIABLE_END; }
<WAITING_TEMPLATE_VAR_VALUE> {ESCAPE_CHAR}                   { yybegin(WAITING_TEMPLATE_VAR_VALUE_ESC); return CptTypes.TEMPLATE_VARIABLE_VALUE; }

<WAITING_TEMPLATE_VAR_VALUE_ESC> ({CRLF}|{ANY_CHAR}){WHITE_SPACE}*  { yybegin(WAITING_TEMPLATE_VAR_VALUE); return CptTypes.TEMPLATE_VARIABLE_VALUE; }


({CRLF}|{WHITE_SPACE})+                                      { yybegin(YYINITIAL); return TokenType.WHITE_SPACE; }

.                                                            { return TokenType.BAD_CHARACTER; }
